package fuse.LaCollaFS;

import java.io.IOException;
import java.io.StringWriter;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;

import LaColla.Api.Api;

import fuse.LaCollaFS.Api.ApiServer;

public class Paxos {
	private ApiServer aserv;

	private Api api;

	private static Operacions o;

	private int Ultim;

	// private static Hashtable<Integer, Boolean> Resolts;

	// private static Hashtable<Integer, Integer> Negat;
	private String groupId = "hola";

	public Paxos(ApiServer a, Api b, Operacions c) {
		aserv = a;
		api = b;
		o = c;
		Ultim = 0;
		// Resolts = new Hashtable<Integer, Boolean>();
	}

	public void IniAccept(int N, String V) {
		p("Paxos : Llenço l'Accept!");
		ArrayList members = aserv.getMembers();
		String memberId = aserv.getMemberId();

		try {
			api.sendInstantMessage(memberId, groupId, V, members);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public void Accept(int N, String V) {

		ArrayList members = aserv.getMembers();
		String memberId = aserv.getMemberId();
		p("Paxos.Accept: Inici.........");
		if (N >= Ultim) {
			Ultim = N;

			// root.setName("Accepted");

			V = V.replace("Accept", "Accepted");
			p("Paxos.Accept: V :" + V);
			try {
				api.sendInstantMessage(memberId, groupId, V, members);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}else{
			p("Accept no acceptat, N("+N+") inferior a Últim("+Ultim+")");
		}

	}

	public void Accepted(int N, String member, Element root) {
		p("Paxos : Accepted!");

		if (Ultim >= N) {
			List l;
			Element e;
			l = root.getChildren();
			e = (Element) l.get(1);
			String Operacio = e.getValue();
			e = (Element) l.get(0);
			String path = e.getValue();
			e = (Element) l.get(2);
			int id = Integer.valueOf(e.getValue());

			p("Paxos: Operacio = " + Operacio);

			if (Operacio.equals("CanviarStat")) {
				p("Paxos: Operació a fer : " + Operacio + " amb el path : "
						+ path);

				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("CrearNode")) {
				p("Paxos: Operació a fer : " + Operacio + " amb el path : "
						+ path);

				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("LlegirDir")) {
				p("Paxos: Operació a fer : " + Operacio + " amb el path : "
						+ path);

				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("EliminarDir")) {
				p("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

				/*	} else if (Operacio.equals("LlegirFitxer")) {
				p("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}*/

			} else if (Operacio.equals("EscriureFitxer")) {
				p("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("EliminarFitxer")) {
				p("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("MoureNode")) {
				p("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("LlegirEnllas")) {
				System.out.println("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}

			} else if (Operacio.equals("CrearEnllas")) {
				System.out.println("Operació a fer : " + Operacio);
				ArrayList op = o.BuscarperPath(path);

				if (op == null) {
					o.AfegirOperacio(id, path, member, Operacio);
				} else {
					// vull canviar l'estat d'un node. Que pot afectar? un altre

					o.AfegirOperacio(id, path, member, Operacio);
				}
			}
			// Resolts.put(id, true);
			p("PAXOS: Consens arribat, decisió presa-----------------------");
		}else{
			p("Consens anterior, no faig res.");
		}
	}

	private static void p(Object o) {
		// System.out.println(o);

	}

	public void Any(int N, String member, String Recovery) {

	}

	public boolean TincLider() {

		return false;
	}

	/*
	 * public void Rebut(int id, String userId, Element root) { Resolts.put(id,
	 * true); p("PAXOS: Rebut id : " + id); }
	 */
	public static boolean Finalitzat(int id, String path) {
		Boolean pucprocedir = true;
		Integer p = -1;

		ArrayList op = o.BuscarperPath(path);
		if (op != null) {
			ArrayList l = (ArrayList) op.get(0);
			if (l != null)
				p = (Integer) l.get(2);
			else
				p("Paxos.Finalitzat: Operació encara pendent path: " + l.get(0)
						+ " operacio: " + l.get(1) + " id " + l.get(2)
						+ " member " + l.get(3));

		}
		pucprocedir = (p == id);

		// } catch (Exception e) {
		// p("Paxos: Error en el Finalitza" + e);
		// }
		p("Paxos.Finalitzat? b(Puc procedir...) :" + pucprocedir + " id : "
				+ id);
		return pucprocedir;
	}

	public void Acabat(int i) {
		o.TreureOperacio(i);

	}

	public int Ultim() {
		return Ultim;
	}

}